package com.lagou.edu.factory;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BeanFactory {
    // 解析xml ,通過反射实例化存储
    // 对外提供实例化对象接口
    private static Map<String, Object> map = new HashMap<>();

    static {
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
        SAXReader saxReader = new SAXReader();
        try {
            Document document = saxReader.read(resourceAsStream);
            Element rootElement = document.getRootElement();
            List<Element> list = rootElement.selectNodes("//bean");
            // 实例化bean对象
            for (int i = 0; i < list.size(); i++) {
                Element element = list.get(i);
                String id = element.attributeValue("id");
                String aClass = element.attributeValue("class");

                Class<?> aClass1 = Class.forName(aClass);// 通过反射获取aClass对象
                Object o = aClass1.newInstance();//获取实例化对象
                map.put(id, o);//封装入map中  key 为配置文件中的id value 为 class具体的实例化对象
            }
            // 维护bean之间的依赖关系
            /**
             *
             * <bean id = "connectionUtils" class = "com.lagou.edu.utils.ConnectionUtils"></bean>
             *
             *  <bean id="accountDao" class="com.lagou.edu.dao.impl.JdbcTemplateDaoImpl">
             *      <property name="ConnectionUtils" ref="connectionUtils"/>
             *  </bean>
             */
            List<Element> propertyNodes = rootElement.selectNodes("//property"); // 读取配置文件中的property标签
            for (int i = 0; i < propertyNodes.size(); i++) {
                Element element = propertyNodes.get(i);
                String name = element.attributeValue("name");
                String ref = element.attributeValue("ref");
                String parentId = element.getParent().attributeValue("id");// 读取父类标签id
                Object parentObject = map.get(parentId); // 从map获取具体的对象
                Method[] methods = parentObject.getClass().getMethods();// 获取父类中的所有方法
                for (int j = 0; j < methods.length; j++) {
                    Method method = methods[j];
                    /**
                     *  获取类中的set方法（这里使用到了name 因此xml中的property 中的name属性不能随便写）
                     */
                    if (("set" + name).equalsIgnoreCase(method.getName())) {
                        Object propertyObject = map.get(ref);// 获取被注入的实例对象
                        method.invoke(parentObject, propertyObject); // 使用代理将property标签中的对象注入到父标签类中
                    }
                }
                // 将维护过依赖的对象重新放入map中，这样再次获取对象时就是有依赖关系的bean对象
               // map.put(parentId, parentObject);
            }

        } catch (DocumentException | ClassNotFoundException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    // 对外提供获取bean对象接口
    public static Object getBean(String id) {
        return map.get(id);
    }

}
